package com.xiaoyu.lanling.data;

import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGAVideoEntity;
import com.xiaoyu.base.app.AppContext;
import com.xiaoyu.base.utils.FileUtil;
import com.xiaoyu.base.utils.ListUtil;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import in.srain.cube.cache.DiskFileUtils;
import in.srain.cube.concurrent.AppThreads;
import in.srain.cube.request.JsonData;
import in.srain.cube.update.DownloadTask;
import in.srain.cube.util.CLog;
import io.reactivex.Single;

public class SvgaData {

    public static final String TAG = SvgaData.class.getSimpleName();

    public static final String LOCAL_PATH = DiskFileUtils.wantFilesPath(AppContext.getContext(), true);
    public static final String SVGA_DIR = "svga";
    public static final String SVGA_DIR_PATH = LOCAL_PATH + File.separator + SVGA_DIR;

    private static final SvgaData INSTANCE = new SvgaData();

    private static SVGAParser mSvgaParser = SVGAParser.Companion.shareParser();

    public static SvgaData getInstance() {
        return INSTANCE;
    }

    private SvgaData() {
        SVGAParser.Companion.shareParser().init(AppContext.getContext());
    }

    private Map<String, SvgaInfo> svgaInfoMap = new HashMap<>();

    private SvgaInfo getSvgaByKey(String key) {
        return svgaInfoMap.get(key);
    }

    synchronized void prepareSvga(JsonData jsonData) {
        Iterator<String> moduleKeys = jsonData.keys();
        while (moduleKeys.hasNext()) {
            String moduleKey = moduleKeys.next();
            JsonData moduleData = jsonData.optJson(moduleKey);

            Iterator<String> funcKeys = moduleData.keys();
            while (funcKeys.hasNext()) {
                String funcKey = funcKeys.next();
                JsonData funcData = moduleData.optJson(funcKey);

                List<JsonData> svgaDataList = funcData.toList();
                for (JsonData svgaData : svgaDataList) {
                    String prefixKey = moduleKey + "_" + funcKey + "_";
                    SvgaInfo svgaInfo = new SvgaInfo(prefixKey, svgaData);
                    svgaInfoMap.put(svgaInfo.key, svgaInfo);
                }
            }
        }
    }

    synchronized void downloadSvgaJsonFile(boolean force) {
        List<DownloadTask> downloadTaskList = new LinkedList<>();

        Set<String> keys = svgaInfoMap.keySet();
        for (String key : keys) {
            SvgaInfo svgaInfo = getSvgaByKey(key);
            if (svgaInfo == null) {
                continue;
            }
            if (force || !svgaInfo.hasLocalFile()) {
                SvgaJsonInfo jsonInfo = svgaInfo.getJsonInfo();
                String jsonPath = SVGA_DIR_PATH + File.separator + jsonInfo.fileName;
                downloadTaskList.add(new DownloadTask(null, jsonInfo.remoteUrl, jsonPath, true));
            }
        }

        for (DownloadTask downloadTask : downloadTaskList) {
            AppThreads.runOnIOThread(downloadTask);
        }
    }

    @NonNull
    public static Single<SVGAVideoEntity> createTaskFromAsset(@NonNull String key) {
        return Single.create(emitter -> {
            String assetPath = SvgaData.SVGA_DIR + File.separator + key;
            mSvgaParser.decodeFromAssets(assetPath, new SVGAParser.ParseCompletion() {
                @Override
                public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
                    emitter.onSuccess(svgaVideoEntity);
                }

                @Override
                public void onError() {
                    emitter.onError(new Throwable("SvgaTask excute failed."));
                }
            });
        });
    }

    @NonNull
    public static Single<SVGAVideoEntity> createTask(@NonNull String key) {
        return Single.create(emitter -> {
            CLog.d(TAG, "createSvgaTask() key=%s", key);
            SvgaData.SvgaInfo svgaInfo = SvgaData.getInstance().getSvgaByKey(key);

            if (svgaInfo == null) {
                CLog.e(TAG, "SvgaInfo initiated failed, key = " + key);
                return;
            }

            boolean hasLocal = svgaInfo.hasLocalFile();
            CLog.d(TAG, "hasLocal=%s", hasLocal);
            if (hasLocal) {
                try {
                    String diskPath = SVGA_DIR_PATH + File.separator + svgaInfo.jsonInfo.fileName;
                    File imageFile = new File(diskPath);
                    InputStream inputStream = new FileInputStream(imageFile);
                    mSvgaParser.decodeFromInputStream(inputStream, key, new SVGAParser.ParseCompletion() {
                        @Override
                        public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
                            emitter.onSuccess(svgaVideoEntity);
                        }

                        @Override
                        public void onError() {
                            CLog.e(TAG, "SvgaInfo excute from stream failed, key = " + key);
                            emitter.onError(new Throwable("SvgaInfo excute from stream failed"));
                        }
                    }, true);

                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                    emitter.onError(e);
                }
            }

            boolean hasAsset = svgaInfo.hasAssetFile();
            CLog.d(TAG, "hasAssets=%s", hasAsset);
            if (hasAsset) {
                String assetPath = SvgaData.SVGA_DIR + File.separator + svgaInfo.jsonInfo.fileName;
                mSvgaParser.decodeFromAssets(assetPath, new SVGAParser.ParseCompletion() {
                    @Override
                    public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
                        emitter.onSuccess(svgaVideoEntity);
                    }

                    @Override
                    public void onError() {
                        CLog.e(TAG, "SvgaInfo excute from assets failed, key = " + key);
                        emitter.onError(new Throwable("SvgaInfo excute from assets failed"));
                    }
                });
                return;
            }

            boolean hasRemoteUrl = svgaInfo.hasRemoteResource();
            CLog.d(TAG, "hasRemoteUrl=%s", hasRemoteUrl);
            if (hasRemoteUrl) {
                mSvgaParser.decodeFromURL(new URL(svgaInfo.jsonInfo.remoteUrl), new SVGAParser.ParseCompletion() {
                    @Override
                    public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
                        emitter.onSuccess(svgaVideoEntity);
                    }

                    @Override
                    public void onError() {
                        CLog.e(TAG, "SvgaInfo excute from URL failed, key = " + key);
                        emitter.onError(new Throwable("SvgaInfo excute from URL failed"));
                    }
                });
                return;
            }
            emitter.onError(new Throwable("Svga file not find"));
        });
    }

    public static class SvgaInfo {

        private final String key;
        private final SvgaJsonInfo jsonInfo;

        private SvgaInfo(String prefixKey, JsonData jsonData) {
            final String jsonUrl = jsonData.optString("svga_url");
            final String originFileName = FileUtil.getFileNameFromRemoteUrl(jsonUrl);

            key = prefixKey + originFileName;
            this.jsonInfo = new SvgaJsonInfo(key, jsonUrl);

        }

        public boolean hasLocalFile() {
            return FileUtil.isFileExist(SVGA_DIR_PATH + File.separator + jsonInfo.fileName);
        }

        public boolean hasAssetFile() {
            final List<String> assetsJsonList;
            try {
                if (AppContext.getContext() == null || AppContext.getContext().getAssets() == null) {
                    return false;
                }

                assetsJsonList = Arrays.asList(AppContext.getContext().getAssets().list("svga"));
                if (ListUtil.isNullOrEmpty(assetsJsonList)) {
                    return false;
                }
                if (!assetsJsonList.contains(jsonInfo.fileName)) {
                    return false;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }

        public boolean hasRemoteResource() {
            if (jsonInfo == null) {
                return false;
            }
            if (TextUtils.isEmpty(jsonInfo.remoteUrl)) {
                return false;
            }

            return true;
        }

        public String getKey() {
            return key;
        }

        public SvgaJsonInfo getJsonInfo() {
            return jsonInfo;
        }

    }

    public static class SvgaJsonInfo {
        private final String fileName;
        private final String remoteUrl;

        private SvgaJsonInfo(String fileName, String remoteUrl) {
            this.remoteUrl = remoteUrl;
            this.fileName = fileName;
        }

        public String getFileName() {
            return fileName;
        }

        public String getRemoteUrl() {
            return remoteUrl;
        }
    }

}
